/*
 * Copyright (C) <2009>
 *
 * <Rishi B Agrawal> <Sneha Hendre>
 * <rishi.b.agrawal@gmail.com> <sneha.hendre@gmail.com>
 *
 * This program is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 3 of the License, or (at your
 * option) any later version->
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE->  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <pwd.h>
#include <sys/types.h>
#include <libxml/xmlmemory.h>
#include <libxml/parser.h>
#include "../include/ohsm.h"
#include "ohsm_u.h"


unsigned char flg_i_usr = UNSET, flg_usr = UNSET;
unsigned char flg_i_grp = UNSET, flg_grp = UNSET;
unsigned char flg_i_types = UNSET, flg_types = UNSET;

int
parseinfo (xmlDocPtr doc, xmlNodePtr cur, unsigned int *users,
	   unsigned int *groups, unsigned int *types)
{

  xmlChar *key;
  int temp;
  int no;

  cur = cur->xmlChildrenNode;
  cur = cur->next;

  while (cur != NULL) {
	if ((!xmlStrcmp(cur->name, (const xmlChar *) "NR_USERS"))) {
		flg_i_usr = SET;
		key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
		temp = validate_key(key);

		if (temp == -1) {
	      no = (int) xmlGetLineNo(cur);
	      fprintf(stderr,
		       "\nOHSM: [%d] : wrong value in <info><users> tag", no);
	      fprintf(stderr,
		       "\nOHSM: [%d] : fatal : cannot proceed further", no);
	      return -1;
	    } 
		else 
	      *users = temp;

#ifdef ALL_DEBUG
	  fprintf(stderr,"\nOHSM: The Number of users : %u", *users);
#endif
	  xmlFree(key);
	}
	cur = cur->next->next;

	if ((!xmlStrcmp(cur->name, (const xmlChar *) "NR_GROUPS"))) {
		flg_i_grp = SET;
		key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
		temp = validate_key (key);

		if (temp == -1) {
			no = (int) xmlGetLineNo(cur);
	      	fprintf(stderr,
		       "\nOHSM: [%d] : wrong value in <info><groups> tag",
		       no);
	      	fprintf(stderr,
		       "\nOHSM: [%d] : fatal : cannot proceed further", no);
	      	return -1;
	    }
	    else
	      *groups = temp;

#ifdef ALL_DEBUG
		fprintf(stderr,"\nOHSM: Number of Groups = %u\n", *groups);
#endif
		xmlFree(key);
	}
	cur = cur->next->next;

	if ((!xmlStrcmp(cur->name, (const xmlChar *) "NR_TYPES"))) {
		flg_i_types = SET;
		key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
		temp = validate_key (key);

		if (temp == -1) {
			no = (int) xmlGetLineNo(cur);
			fprintf(stderr,
				"\nOHSM: [%d] : wrong value in <info><types> tag", no);
			fprintf(stderr,
				"\nOHSM: [%d] : fatal : cannot proceed further", no);
			return -1;
		}
		else
			*types = temp;

#ifdef ALL_DEBUG
		fprintf(stderr,"\nOHSM: Number of Types = %u\n", *types);
#endif
		xmlFree(key);
	}
    cur = cur->next->next;
  }

  if (flg_i_usr == UNSET)
      *users = 0;
  if (flg_i_grp == UNSET)
      *groups = 0;
  if (flg_i_types == UNSET)
      *types = 0;

  return 0;
}


int
parseuser (xmlDocPtr doc, xmlNodePtr cur, const unsigned int number)
{

  xmlChar *key;

  int temp, no;
  int cnt_users = 0, retval;
  cur = cur->xmlChildrenNode;
  cur = cur->next;
  while (cur != NULL) {
	if ((!xmlStrcmp(cur->name, (const xmlChar *) "USER"))) {
		flg_usr = SET;
		cnt_users++;

		if (cnt_users > number) {
			no = (int) xmlGetLineNo(cur);
			printf
			("\nOHSM: error number of users in <info><users>\
			 is less than the entered users");
			return -1;
		}
		else {
			key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
			temp = validate_key (key);

			if (temp == -1) {
				no = (int) xmlGetLineNo(cur);
				fprintf(stderr,"\nOHSM: [%d] :\
						wrong value in <user> tag",	no);
				fprintf(stderr,	"\nOHSM: [%d] : fatal :\
					cannot proceed further", no);
				return -1;
			}

			retval = validate_user (temp);
			if (retval)
				allocpol->uid_tier[allocpol->uidx].uid = temp;
			else {
				no = (int) xmlGetLineNo(cur);
				fprintf(stderr,"\nOHSM: [%d] :\
						wrong value in <user> tag",	no);
				fprintf(stderr,"\nOHSM: [%d] :\
					user does not exists", temp);
			}
	    	xmlFree(key);
		}
  	}
    cur = cur->next;

	if ((!xmlStrcmp(cur->name, (const xmlChar *) "TIER"))) {
		key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
		temp = validate_key (key);

		if (temp == -1) {
			fprintf(stderr,"\nOHSM: Invalid tier entered");
			return -1;
	    }
	  allocpol->uid_tier[allocpol->uidx++].tier = temp;
	  xmlFree(key);
	}
      cur = cur->next->next;
    }

  if (cnt_users < number) {
      no = (int) xmlGetLineNo(cur);
      printf
	("\nOHSM: Number of users in <info> greater than users specified");
      return -1;
  }
  return 0;			//sucessful
}

int
parsegroup(xmlDocPtr doc, xmlNodePtr cur, unsigned int groups)
{

  xmlChar *key;
  unsigned int temp_gid;
  unsigned int cnt_groups = 0;
  int retval, temp, no;

  cur = cur->xmlChildrenNode;
  cur = cur->next;
  while (cur != NULL)
    {

      if ((!xmlStrcmp(cur->name, (const xmlChar *) "GROUP")))
	{
	  flg_grp = SET;
	  cnt_groups++;

	  if (cnt_groups > groups)
	    {
	      no = (int) xmlGetLineNo(cur);
	      printf
		("\nOHSM: error number of groups in <info><groups> is less than the entered groups");
	      return -1;

	    }
	  else
	    {

	      key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	      temp = validate_key (key);

	      if (temp == -1)
		{
		  no = (int) xmlGetLineNo(cur);
		  fprintf(stderr,
			   "\nOHSM: [%d] : wrong value in <group> tag", no);
		  fprintf(stderr,
			   "\nOHSM: [%d] : fatal : cannot proceed further",
			   no);
		  return temp;
		}
	      retval = validate_group(temp);
	      if (retval >= 0)
		{
		  allocpol->gid_tier[allocpol->gidx].gid = temp;
		}
	      else
		{
		  no = (int) xmlGetLineNo(cur);
		  fprintf(stderr,
			   "\nOHSM: [%d] : error %u gid not present on system",
			   no, temp);
		}
	      xmlFree(key);
	    }
	}
      cur = cur->next;

      if ((!xmlStrcmp(cur->name, (const xmlChar *) "TIER")))
	{
	  key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	  temp = validate_key (key);

	  if (temp == -1)
	    {
	      no = (int) xmlGetLineNo(cur);
	      fprintf(stderr,"\nOHSM: [%d] : wrong value in <group> tag",
		       no);
	      fprintf(stderr,"\nOHSM: [%d]: fatal : cannot proceed further",
		       no);
	      return temp;
	    }
	  allocpol->gid_tier[allocpol->gidx++].tier = temp;
	  xmlFree(key);
	}
      cur = cur->next->next;
    }
  if (cnt_groups < groups)
    {
      no = (int) xmlGetLineNo(cur);
      printf
	("\nOHSM: %u %u: error number of groups in <info> greater than groups spcified",
	 cnt_groups, groups);
    }
  return 0;
}

int
parsetypes (xmlDocPtr doc, xmlNodePtr cur, unsigned int types)
{

  xmlChar *key;
  unsigned int cnt_types = 0;
  char *temp_name = NULL;
  int temp, no;

  cur = cur->xmlChildrenNode;
  cur = cur->next;
  while (cur != NULL)
    {

      if ((!xmlStrcmp(cur->name, (const xmlChar *) "TYPE")))
	{
	  flg_types = SET;
	  cnt_types++;

	  if (cnt_types > types)
	    {
	      no = (int) xmlGetLineNo(cur);
	      printf
		("\nOHSM:  %u %u : error number of types in <info><types> is less than the entered types",
		 cnt_types, types);
	      break;

	    }
	  else
	    {
	      key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	      temp_name = (char *) key;
	      strcpy(allocpol->type_tier[allocpol->tidx].type, temp_name);
	      xmlFree(key);
	    }
	}
      cur = cur->next->next;

      if ((!xmlStrcmp(cur->name, (const xmlChar *) "TIER")))
	{

	  key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	  temp = validate_key (key);

	  if (temp == -1)
	    {
	      no = (int) xmlGetLineNo(cur);
	      fprintf(stderr,"\nOHSM: [%d] : wrong value in <tier> tag",
		       no);
	      fprintf(stderr,"\nOHSM: [%d]: fatal : cannot proceed further",
		       no);
	      return temp;
	    }
	  else
	    {
	      allocpol->type_tier[allocpol->tidx++].tier = temp;
	      xmlFree(key);
	    }
	}
      cur = cur->next->next;
    }

  if (cnt_types < types)
    {
      no = (int) xmlGetLineNo(cur);
      printf
	("\nOHSM: %u %u: error number of types in <info> greater than types spcified",
	 cnt_types, types);
      return -1;
    }
  return 0;
}

int
parsedoc (char *docname)
{

  xmlDocPtr doc;
  xmlNodePtr cur;
  unsigned int users, groups, types;
  int retval;

  xmlLineNumbersDefault(1);
  doc = xmlParseFile(docname);
  if (!doc)
    {
      fprintf(stderr,"\nOHSM: Document not parsed successfully");
      xmlFreeDoc(doc);
      return -1;
    }

  cur = xmlDocGetRootElement(doc);
  if (cur == NULL)
    {
      fprintf(stderr,"\nOHSM: empty document");
      xmlFreeDoc(doc);
      return -1;
    }

  if (xmlStrcmp(cur->name, (const xmlChar *) "ALLOC_POLICY"))
    {
      fprintf(stderr,
	       "\nOHSM: Invalid document Root element not equal to create...");
      xmlFreeDoc (doc);
      return -1;
    }

  cur = cur->xmlChildrenNode;
  cur = cur->next;
  while (cur != NULL) {
      if ((!xmlStrcmp(cur->name, (xmlChar *) "INFO"))) {
	  	retval = parseinfo(doc, cur, &users, &groups, &types);
	  	if (retval)
	    	return retval;
	  	allocpol->cnt_users = users;
	  	allocpol->cnt_groups = groups;
	  	allocpol->cnt_types = types;
	  }

	  cur = cur->next->next;
      if ((!xmlStrcmp(cur->name, (const xmlChar *) "USERS"))) {
	  	if (users) {
	      retval = parseuser(doc, cur, users);
	      if (retval)
		  	return retval;
	    }
	  }

	  cur = cur->next->next;
      if ((!xmlStrcmp(cur->name, (const xmlChar *) "GROUPS"))) {
		if (groups) {
	      retval = parsegroup(doc, cur, groups);
	      if (retval)
		  	return retval;
	    }
	  }

	cur = cur->next->next;
	if ((!xmlStrcmp(cur->name,(const xmlChar *) "TYPES"))) {
		if (types) {
	      retval = parsetypes(doc, cur, types);
	      if (retval)
			return retval;
	    }
	  }
      cur = cur->next->next;
  }
  xmlFreeDoc(doc);
  return 0;
}


int
ohsm_get_allocation_policy(char *filename)
{

  int retval;
  char cmd[80];

  fprintf(stderr, cmd, "xmllint --valid --noout %s", filename);
  retval = system(cmd);
  if (!retval) {
	retval = parsedoc(filename);
	if (retval)
		return -1;
  }

  if (retval) {
	if (flg_grp ^ flg_i_grp) {
		fprintf(stderr,
		   "\nOHSM: [%s] : error GRP and <groups> tag mismatch ",
		   filename);
	}

	if (flg_usr ^ flg_i_usr) {
		fprintf(stderr,
		   "\nOHSM [%s] : error USER and <users> tag mismatch ",
		   filename);
	}

	if (flg_types ^ flg_i_types) {
		fprintf(stderr,
			"\nOHSM [%s] : error TYPE and <types> tag mismatch ",
			filename);
	}
  }
  return retval;
}
